import ij.IJ;
import ij.ImagePlus;
import ij.gui.NewImage;
import ij.plugin.PlugIn;
import ij.process.Blitter;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.Locale;
import java.util.Random; 
import java.util.Scanner;

import pluginUtils.Complexe;
import pluginUtils.Doublet;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Punkt;
import pluginUtils.Quadrilatere;
import pluginUtils.Transformation;
//import pluginUtils.Transformation;
import pluginUtils.Vector2D;


// Anamorph est gele : on poursuit les developpements ici
// en parallele avec anamorphose5.pov
// 1) position de l'ecran // done
// 2) echelle et centrage de l'image // done
// 3) interpolation et suppression des zones noires. // done

public class Anamorph4 extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	
	private ImageProcessor primeIP; 
	private int X=2800,Y=2100; // image size
	
	
	private double xShift=0; 
	private double zShift=0; 
	
	private Random gene=new Random(); 
	
	
	
	
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	


	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu;
		 
	}
	
	private void drawPoint(Punkt p){
		double xCenter=p.getY(); 
		double yCenter=p.getZ(); 
		int intX=(int)(xCenter*acoef+ccoef);
		int intY=(int)(yCenter*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		//System.out.println("---->"+XD+" "+YD+" "+XF+" "+YF); 
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
	private void drawLine(Punkt A,Punkt B){
		drawLine(A.getY(),A.getZ(),B.getY(),B.getZ()); 
	}
	
	
	
	public void run(String arg) {
		System.out.println("go");
		//primeIP = new ColorProcessor(X,Y);
		
		ImagePlus imp = IJ.openImage("/tmp/MonaLisaCarre2.png");
		//ImagePlus imp=IJ.openImage("C:/Documents and Settings/Francesco/Mes documents/Mona_Lisacarre.png");
		imp.setTitle("PrimeIP");
		
	
		System.out.println(imp); 
		primeIP=imp.getProcessor();
		X=primeIP.getWidth(); 
		Y=primeIP.getHeight(); 
		
        setStack(null, imp.getStack());
        setCalibration(imp.getCalibration()); 
		
        	show();
		
		
		

		// create a new image with the same size and copy the pixels of the original image
		ImagePlus inverted = NewImage.createRGBImage ("Inverted image", primeIP.getWidth(), primeIP.getHeight(), 1, NewImage.FILL_BLACK);
		ImageProcessor inv_ip = inverted.getProcessor();
		//inv_ip.copyBits(ip,0,0,Blitter.COPY);
		//int[] pixels = (int[]) inv_ip.getPixels();
		
		for(int i=0;i<primeIP.getWidth();i++)
			for(int j=0;j<primeIP.getHeight();j++)
				inv_ip.putPixel(i,j,1214); 
		
		
		
		
		
		
		
		
		
		/*
		Polygon background=new Polygon(new int[]{0,0,X,X},new int[]{0,Y,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		*/
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.RED);
		primeIP.setLineWidth(3); 
	
		setProcessor("Verifying", primeIP);
		
		drawLine(x0,0,x1,0);
		drawLine(0,y0,0,y1);
		
	
		
		System.out.println("***** "+x0+" "+x1+" "+y0+" "+y1); 
		 HashMap<Doublet,Punkt> lesPoints=new HashMap<Doublet,Punkt>();
		 HashMap<Doublet,Quadrilatere>lesCarres =new HashMap<Doublet,Quadrilatere>();
		 HashMap<Doublet,Quadrilatere>QuadrillageDeBase =new HashMap<Doublet,Quadrilatere>();
		 String ligne="rien"; 
		 
		try{
			 File source = new File("/tmp/quadri2.txt");
			//File source=new File("C:/Documents and Settings/Francesco/Mes documents/T�l�chargements/eclipse-SDK-3.5.1-win32/eclipse/quadri.txt"); 
			
			 BufferedReader in = new BufferedReader(new FileReader(source));
             ligne = in.readLine();
            
             while(true){
            	 Scanner rl=new Scanner(ligne); 
                 rl.useLocale(Locale.US);
                 int a= rl.nextInt(); 
                 int b=rl.nextInt(); 
                 double c=rl.nextDouble(); 
                 double d=rl.nextDouble(); 
                 lesPoints.put(new Doublet(a,b),new Punkt(a,b,c,d)); 
                 ligne=in.readLine();
                 System.out.println(ligne); 
             }
             
		}
		
		
		catch(InputMismatchException e){System.out.println("Fin de la lecture du fichier "+ligne);}
		catch(Exception e){System.out.println(e);   }
	
		double minx=10000; 
		double miny=10000; 
		double maxx=-10000; 
		double maxy=-10000; 
		int mina=10000; 
		int maxa=-10000; 
		int minb=10000; 
		int maxb=-10000; 
		// tous les points sont lus, fabriquer les quadrilateres;
		
		double scale=1;
		 
		
		for(Doublet d:lesPoints.keySet()){
			int a=d.getA(); 
			int b=d.getB();
			
			
			if (lesPoints.containsKey(new Doublet(a,b+1))&& // B
					lesPoints.containsKey(new Doublet(a+1,b))&& //C 
					lesPoints.containsKey(new Doublet(a+1,b+1))) //D
			{
				
				if(a<mina) mina=a; 
				if(a>maxa) maxa=a; 
				if(b<minb) minb=b; 
				if(b>maxb) maxb=b; 
			
				Punkt A=lesPoints.get(new Doublet(a,b)); 
				double vx=A.getY(); 
				double vy=A.getZ(); 
				if(vx<minx) minx=vx; 
				if(vy<miny) miny=vy; 
				if(vx>maxx) maxx=vx; 
				if(vy>maxy) maxy=vy;
				A=new Punkt(0,0,scale*vx,scale*vy); 
				Punkt B=lesPoints.get(new Doublet(a,b+1)); 
				vx=B.getY(); 
				vy=B.getZ(); 
				if(vx<minx) minx=vx; 
				if(vy<miny) miny=vy; 
				if(vx>maxx) maxx=vx; 
				if(vy>maxy) maxy=vy;
				B=new Punkt(0,0,scale*vx,scale*vy); 
				Punkt C=lesPoints.get(new Doublet(a+1,b));
				vx=C.getY(); 
				vy=C.getZ(); 
				if(vx<minx) minx=vx; 
				if(vy<miny) miny=vy; 
				if(vx>maxx) maxx=vx; 
				if(vy>maxy) maxy=vy;
				C=new Punkt(0,0,scale*vx,scale*vy); 
				Punkt D=lesPoints.get(new Doublet(a+1,b+1));
				vx=D.getY(); 
				vy=D.getZ(); 
				if(vx<minx) minx=vx; 
				if(vy<miny) miny=vy; 
				if(vx>maxx) maxx=vx; 
				if(vy>maxy) maxy=vy;
				D=new Punkt(0,0,scale*vx,scale*vy); 
				lesCarres.put(d,new Quadrilatere(A,B,C,D));
			}
			
		
			
		}// for Doublet 
		
		
		System.out.println(minx+" "+maxx+" "+miny+" "+maxy);
		System.out.println(mina+" "+maxa+" "+minb+" "+maxb);
		
		/*
		// Ce bout de code donne l'image du quadrillage apres reflection
		setBounds(minx,maxx,miny,maxy); 
		setCoefs(); 

		for(Doublet d:lesCarres.keySet()){
			Quadrilatere q=lesCarres.get(d);
			drawLine(q.getUl(),q.getUr());
			drawLine(q.getUl(),q.getLl()); 
			drawLine(q.getLl(),q.getLr()); 
			drawLine(q.getLr(),q.getUr());		
			System.out.println(q);
		}
		
		for(Doublet d: lesPoints.keySet())
		{
			Punkt pp=lesPoints.get(d);
			drawPoint(pp); 
			
		}
			
		show(); 
		int kp=0; 
		while(kp==0) kp=0;
		*/
		
		
		
		
		
		// construire le quadrillage de l'image
		
		int nbCarrY=maxa-mina;
		int nbCarrX=maxb-minb; 
		double stepy=primeIP.getWidth()/(nbCarrY+0.0);
		double stepx=primeIP.getHeight()/(nbCarrX+0.0);
		int stepyInt=primeIP.getWidth()/nbCarrY;
		int stepxInt=primeIP.getHeight()/nbCarrX;
		System.out.println(stepx+" "+stepy); 
		
	
		

		
		
		
		double scaleb=0.1;
		
		double ma=(maxx-minx)/2; 
		double mb=(maxy-miny)/2; 
		double mc=Math.max(ma,mb); 
	
		setBounds(-scaleb*mc,scaleb*mc,-scaleb*mc,scaleb*mc);
		//setBounds(scaleb*minx,scaleb*maxx,scaleb*miny,scaleb*maxy);
		setCoefs(); 
		
		for(int xa=mina; xa<maxa;xa++)
			for(int xb=minb;xb<maxb;xb++){
				if(lesCarres.containsKey(new Doublet(xa,xb))){
					// Calculer le quadrilatere
					
					Punkt A=new Punkt(xa,xb,(xa-mina)*stepy,(xb-minb)*stepx); 
					Punkt B=new Punkt(xa+1,xb,(xa+1-mina)*stepy,(xb-minb)*stepx);
					Punkt C=new Punkt(xa,xb+1,(xa-mina)*stepy,(xb+1-minb)*stepx);
					Punkt D=new Punkt(xa+1,xb+1,(xa+1-mina)*stepy,(xb+1-minb)*stepx);
					
					
					Quadrilatere nouvo=new Quadrilatere(A,B,C,D);
					QuadrillageDeBase.put(new Doublet(xa,xb), nouvo);
					
					/*
					setBounds(0,primeIP.getWidth()+20,0,primeIP.getHeight()+20);
					setCoefs();
					
					drawLine(nouvo.getUl(),nouvo.getUr());
					drawLine(nouvo.getUl(),nouvo.getLl()); 
					drawLine(nouvo.getLl(),nouvo.getLr()); 
					drawLine(nouvo.getLr(),nouvo.getUr());		
					
					
					
					setBounds(-scaleb*mc,scaleb*mc,-scaleb*mc,scaleb*mc);
					setCoefs(); 
					
					
					*/
					Transformation t=new Transformation(nouvo,lesCarres.get(new Doublet(xa,xb)));
			
					
					double mstepx=0.125; 
					double mstepy=0.125*(X+0.0)/Y; 
					double x=(xa-mina)*stepyInt; 
					while(x<(xa+1-mina)*stepyInt){
						//System.out.println(x); 
						double y=(xb-minb)*stepxInt; 
						while(y<(xb+1-minb)*stepxInt){
							// transformer un point
							Punkt orig=new Punkt(0,0,x,y);
							Punkt dest=t.transforme(orig);
							//System.out.println(x+" "+y+" "+dest.getY()+" "+dest.getZ());
							int col=primeIP.getPixel((int)x,(int)y);
							int col2=inv_ip.getPixel((int)(acoef*dest.getZ()+ccoef), (int)(vcoef*dest.getY()+wcoef));
							if(col2==1214)
							inv_ip.putPixel((int)(acoef*dest.getZ()+ccoef), (int)(vcoef*dest.getY()+wcoef), col);
							
							y=y+mstepy;
						}
						x=x+mstepx;
						System.out.println(x); 
						}
				}
					
					
					
			}// quadrillage image
		
		//inv_ip.fillOval(X/2, Y/2,50,50);
		int arrayProv[][]=new int[X][Y]; 
		
		// interpolation
		// TODO : ordre de X et Y
		for(int i=1;i<X-1;i++)
			for(int j=1;j<Y;j++){
				int c=inv_ip.getPixel(i,j); 
				arrayProv[i][j]=c; 
				if(c==1214){
					int sum=0; 
					int nb=0; 
					for(int x=-1;x<2;x++)
						for(int y=-1;y<2;y++)
							if((x!=0)||(y!=0)){
								int c2=inv_ip.getPixel(i+x,j+y);
								if(c2!=1214){
									sum+=c2; 
									nb++; 
								}
							}// if x,y 
					if(nb!=0) arrayProv[i][j]=sum/nb; 
				}// if c
				
			}// for j
		for(int i=1;i<X-1;i++)
			for(int j=1;j<Y-1;j++) 
				inv_ip.putPixel(i, j, arrayProv[i][j]); 
		
	
		inverted.show();
		System.out.println("affiche "+mc*scaleb*2); 
		
		// Affichage du quadrillage de base
		setBounds(0,primeIP.getWidth()+20,0,primeIP.getHeight()+20);
		setCoefs();
		for(Doublet d:QuadrillageDeBase.keySet()){
			Quadrilatere q=QuadrillageDeBase.get(d);
			drawLine(q.getUl(),q.getUr());
			drawLine(q.getUl(),q.getLl()); 
			drawLine(q.getLl(),q.getLr()); 
			drawLine(q.getLr(),q.getUr());		
			//System.out.println(q);
		}

		show(); 
		
	
		
		}
	}	

	